# -*- coding: utf-8 -*-
# 项目初始化及运行
import traceback
import os
import jpype

import flask
from flask import request
from flask_request_params import bind_request_params
from flask_apscheduler import APScheduler
from pymysql import Date

from SchedulerService import SchedulerApi
from flask import render_template
from random import shuffle


from sqlalchemy import *
import json
import time
import uuid
from uuid import UUID
from sqlalchemy.sql import func
from sqlalchemy import Column, create_engine
from sqlalchemy.dialects.mysql import BIGINT, VARCHAR,INTEGER,CHAR,DATETIME,MEDIUMTEXT,JSON
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

from p2jport import P2JPort
from utils import Utils

app = flask.Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_POOL_SIZE'] = 100
app.config['SQLALCHEMY_MAX_OVERFLOW'] = 5
app.config['SQLALCHEMY_POOL_TIMEOUT'] = 30
app.config['SQLALCHEMY_ECHO'] = True

# 创建对象的基类:
Base = declarative_base()
# 初始化数据库连接:
engine = create_engine('mysql+pymysql://veve_admin:JnzXGddeN48EYSSK@81.70.151.135:3306/veve_space?autocommit=true', convert_unicode=True, pool_size=50, pool_pre_ping=True, pool_recycle=3600)
# 创建DBSession类型:
DBSession = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine))
app.before_request(bind_request_params)
ap_scheduler = APScheduler()
ap_scheduler.init_app(app)
scheduler_api = SchedulerApi()

jarpath = os.path.join(os.path.abspath("."),
                       "/www/server/java/veve-scheduler/target/timeUntilDropBuy-jar-with-dependencies.jar")

# 获取jvm 的文件路径
jvmPath = jpype.getDefaultJVMPath()

# 开启jvm

jpype.startJVM(jvmPath, "-ea", "-Djava.class.path=%s" % (jarpath))

# ②、加载java类（参数是java的长类名）
javaClass = jpype.JClass("com.comic.core.P2JPort")


def current_timestamp(*args, **kwargs):
    return int(time.time())


class ProtocolLog(Base):
    # 表的名字:
    __tablename__ = 'veve_protocol_log'

    # 表的结构:
    id = Column(BIGINT(12), primary_key=True)
    uid = Column(VARCHAR(120))
    content = Column(MEDIUMTEXT())
    client_operation = Column(Enum('PlaceStoreReservation', 'PlaceStoreReservationForBlindbox'))
    update_time = Column(DATETIME(timezone=True), server_default=func.now())


# KpsdkCt:
class KpsdkCt(Base):
    # 表的名字:
    __tablename__ = 'veve_kpsdk_ct'

    # 表的结构:
    id = Column(BIGINT(12), primary_key=True)
    uid = Column(VARCHAR(120))
    x_kpsdk_ct = Column(VARCHAR(200))
    update_time = Column(INTEGER(12))


# ComingSoon:
class ComingSoon(Base):
    # 表的名字:
    __tablename__ = 'veve_coming'

    # 表的结构:
    id = Column(BIGINT(12), primary_key=True)
    drop_id = Column(VARCHAR(64))
    graph_ql_body = Column(JSON)
    is_blindbox = Column(INTEGER(1))
    update_time = Column(INTEGER(12))
    series_item = Column(Enum('uncommon', 'rare', 'ultra'))
    collect_type = Column(Enum('series', 'comic', 'collectible'))
    have_drop = Column(Enum('NO', 'YES'))
    client_operation = Column(VARCHAR(64))
    details_graph_ql = Column(JSON)

# ReserveResult
class ReserveResult(Base):
    # 表的名字:
    __tablename__ = 'veve_results'

    # 表的结构:
    id = Column(BIGINT(12), primary_key=True)
    uid= Column(VARCHAR(64))
    results = Column(JSON)
    create_time = Column(INTEGER(10))


# Hcaptcha token
class HcaptchaToken(Base):
    # 表的名字:
    __tablename__ = 'veve_captcha'
    # 表的结构:
    id = Column(BIGINT(12), primary_key=True)
    token = Column(VARCHAR(7200))
    create_time = Column(INTEGER(10))


# ip pool
class IpResource(Base):
    # 表的名字:
    __tablename__ = 'veve_ip_resource'
    # 表的结构:
    id = Column(BIGINT(12), primary_key=True)
    assign_ip = Column(VARCHAR(120))
    state = Column(CHAR(1))


# 定义User对象:
class User(Base):
    # 表的名字:
    __tablename__ = 'veve_user'

    # 表的结构:
    id = Column(BIGINT(12), primary_key=True)
    uid = Column(VARCHAR(120))
    cookie = Column(VARCHAR(1200))
    client_id = Column(VARCHAR(30))
    client_version = Column(VARCHAR(20))
    client_name = Column(VARCHAR(30))
    client_host = Column(VARCHAR(120))
    client_brand = Column(VARCHAR(120))
    client_model = Column(VARCHAR(120))
    client_manufacturer = Column(VARCHAR(120))


    x_kpsdk_v = Column(VARCHAR(15))
    x_kpsdk_ct = Column(VARCHAR(200))
    user_agent = Column(VARCHAR(400))
    state = Column(CHAR(1))
    crypt_sign = Column(VARCHAR(512))
    username = Column(VARCHAR(32))
    update_time = Column(DATETIME(fsp=6))

    # 新上报字段
    client_carrier = Column(VARCHAR(32))
    client_fingerprint = Column(VARCHAR(150))
    client_hardware = Column(VARCHAR(120))
    client_product = Column(VARCHAR(120))
    client_tags = Column(VARCHAR(120))
    client_adb_enabled = Column(VARCHAR(32))
    client_hook = Column(VARCHAR(32))
    client_development_setting = Column(VARCHAR(32))

    # 特殊字段
    user_type = Column(Enum('common', 'test', 'query', 'disable', 'shift'))

    # 分配ip
    assign_ip = Column(VARCHAR(120))
    email = Column(VARCHAR(64))

    #随机顺序
    request_sort = Column(INTEGER(10))

    #宿主机器名
    host_name = Column(VARCHAR(32))


@app.route('/api/users', methods=['GET'])
def list_user(name=None):
    """用户管理页面
            """
    return render_template('user.html', name=name)


@app.route('/api/veve/captcha', methods=['POST'])
def add_captcha():
    token = request.form.get("token")
    session = DBSession()
    # 创建新User对象:
    create_time = int(time.time())
    captcha = HcaptchaToken(token=token, create_time=create_time)
    # 添加到session:
    session.add(captcha)
    # 提交即保存到数据库:
    session.commit()
    # 关闭session:
    session.close()
    data = dict()
    data['code'] = 'success'
    return json.dumps(data)


@app.route('/api/veve/captcha', methods=['GET'])
def get_token_list():
    session = DBSession()
    # 创建新User对象:
    token_list = session.query(HcaptchaToken).order_by(HcaptchaToken.create_time.desc())
    # 关闭session:
    session.close()
    return json.dumps([{"token": x.token, "create_time": x.create_time} for x in token_list])


@app.route('/api/veve/coming', methods=['GET'])
def get_coming_list():
    try:
        session = DBSession()
        # 创建新User对象:
        coming_list = session.query(ComingSoon).all()
        # 关闭session:
        session.close()
        return json.dumps([{"drop_id": x.drop_id, "graph_ql_body": x.graph_ql_body, "details_graph_ql": x.details_graph_ql,"is_blindbox": x.is_blindbox,
                            "series_item": x.series_item, "have_drop": x.have_drop} for x in coming_list])
    except:
        traceback.print_exc()
        session.rollback()
        session.close()


def _check_uuid4(test_uuid, version=4):
    try:

        return uuid.UUID(test_uuid).version == version
    except ValueError:
        return False


@app.route('/api/veve/coming', methods=['POST'])
def update_coming():
    graph_ql_body = request.form.get("graph_ql_body")
    details_graph_ql = request.form.get("details_graph_ql")
    client_operation = request.form.get("client_operation")
    is_blindbox = request.form.get("is_blindbox", 0)
    collect_type = request.form.get("collect_type")
    have_drop = request.form.get("have_drop", 'YES')
    sign_auth = request.form.get("sign_auth")
    data = dict()
    if not (Utils.getSign() == sign_auth):
        data['code'] = 'error'
        data['msg'] = ' invalid sign auth '
        return json.dumps(data)

    try:
        session = DBSession()
        # 创建新Coming对象:
        # coming = session.query(ComingSoon).first()
        graph_ql_dic = json.loads(graph_ql_body)
        details_graph_ql_dic = json.loads(details_graph_ql)
        drop_id = graph_ql_dic['variables']['id']
        if not _check_uuid4(drop_id, 4):
            data['code'] = 'error'
            data['msg'] = ' invalid drop_id format '
            return json.dumps(data)

        coming = ComingSoon(drop_id=drop_id, graph_ql_body=eval(graph_ql_body), details_graph_ql=details_graph_ql, client_operation=client_operation, is_blindbox=int(is_blindbox), collect_type=collect_type, have_drop=have_drop)
        # 提交即保存到数据库:
        session.add(coming)
        session.commit()
        session.close()
    except:
        traceback.print_exc()
        session.rollback()
        session.close()
        data['code'] = 'error'
        data['msg'] = 'invalid  graph_ql json'
        return json.dumps(data)

    data['code'] = 'success'
    return json.dumps(data)


@app.route('/api/veve/user', methods=['PATCH'])
def assign_user_sort():
    try:
        session = DBSession()
        # 创建新User对象:
        user_list = session.query(User).all()
        shuffle(user_list)
        sort_delta = 1
        for user in user_list:
            user.request_sort = sort_delta
            sort_delta += 1
        session.commit()
        session.close()
    except:
        session.rollback()
        session.close()
    data = dict()
    data['code'] = 'success'
    return json.dumps(data)


@app.route('/api/veve/users', methods=['GET'])
def get_user_list():
    try:
        session = DBSession()
        # 创建新User对象:
        user_list = session.query(User).all()
        # 关闭session:
        session.close()
        return json.dumps([{"uid": x.uid, "username": x.username, "assign-ip": x.assign_ip,
                            "x-kpsdk-ct": x.x_kpsdk_ct} for x in user_list])
    except:
        session.rollback()
        session.close


@app.route('/api/veve/user', methods=['GET'])
def get_user():
    """【用户认证信息】
          username格式： /api/veve/user?username=quifengyang
         @@@
         #### args

         | args | nullable | type | remark |
         |--------|--------|--------|--------|
         |    username    |    false    |    string   |    用户昵称  |

         #### return
         - ##### json
         >  {"code": "success"}
         @@@
         """
    username = request.args.get('username', None)
    try:
        x_session = DBSession()
        # 创建新User对象:
        x = x_session.query(User).filter(User.username == username).first()
        coming = x_session.query(ComingSoon).first()
        # 关闭session:
        x_session.close()

        x_kpsdk_cd = str(javaClass.getX_kpsdk_cd())
        return json.dumps({"uid": x.uid, "username": x.username, "cookie": x.cookie, "client-operation":coming.client_operation, "details_graph_ql":coming.details_graph_ql, "client-host": x.client_host, "client-brand": x.client_brand, "client-model": x.client_model, "client-host": x.client_host, "client-manufacturer": x.client_manufacturer,
                            "x-kpsdk-ct": x.x_kpsdk_ct, "client-id": x.client_id, "client-version": x.client_version, "client-name": x.client_name, "x-kpsdk-v": x.x_kpsdk_v, "user-agent": x.user_agent, "client-carrier": x.client_carrier, "client-fingerprint": x.client_fingerprint, "client-hardware": x.client_hardware,
                           "client-product": x.client_product, "client-tags": x.client_tags, "client-adb-enabled": x.client_adb_enabled, "client-hook": x.client_hook, "client-development-setting": x.client_development_setting, "x-kpsdk-ct": x.x_kpsdk_ct,"x-kpsdk-cd":x_kpsdk_cd,"collect_type": coming.collect_type} )
    except:
        traceback.print_exc()
        x_session.rollback()
        x_session.close


@app.route('/api/veve/user', methods=['POST'])
def add_user():

    sig = request.form.get("sig")
    # if not Utils.getUploadSig().startswith(sig):
    # return json.dumps({'code': 'error', 'msg': 'invalid sig'})

    uid = request.form.get("uid")
    cookie = request.form.get("cookie")
    client_host = request.form.get("client-host")
    client_brand = request.form.get("client-brand")
    client_model = request.form.get("client-model")
    client_manufacturer = request.form.get("client-manufacturer")
    client_id = request.form.get("client-id")
    client_version = request.form.get("client-version")
    client_name = request.form.get("client-name")
    x_kpsdk_v = request.form.get("x-kpsdk-v")
    user_agent = request.form.get("user-agent")
    crypt_sign = request.form.get("crypt-sign")
    username = request.form.get("username")

    # 新上报字段
    client_carrier = request.form.get("client-carrier", "")
    client_fingerprint = request.form.get("client-fingerprint")
    client_hardware = request.form.get("client-hardware")
    client_product = request.form.get("client-product")
    client_tags = request.form.get("client-tags")
    client_adb_enabled = request.form.get("client-adb-enabled")
    client_hook = request.form.get("client-hook")
    client_development_setting = request.form.get("client-development-setting")
    email = request.form.get("email")

    try:
        session = DBSession()
        # 创建新User对象:
        user = session.query(User).filter(User.uid == uid).first()

        if not user:
                new_user = User(uid=uid, cookie=cookie, client_id=client_id, client_version=client_version, client_name=client_name, x_kpsdk_v=x_kpsdk_v,
                                user_agent=user_agent,  crypt_sign=crypt_sign,  client_host=client_host,  client_brand=client_brand,  client_model=client_model,  client_manufacturer=client_manufacturer,
                                client_carrier=client_carrier, client_fingerprint=client_fingerprint, client_hardware=client_hardware, client_product=client_product,
                                client_tags=client_tags, client_adb_enabled=client_adb_enabled, client_hook=client_hook, client_development_setting=client_development_setting,
                                username=username, user_type='common',  email=email, state=1)
                # 添加到session:
                # ip_resource.state = '1'
                session.add(new_user)
                # 提交即保存到数据库:
                session.commit()
                # 关闭session:
                session.close()

        else:
                user.cookie = cookie
                user.client_id = client_id
                user.client_host = client_host
                user.client_brand = client_brand
                user.client_model = client_model
                user.client_manufacturer = client_manufacturer

                user.client_version = client_version
                user.client_name = client_name
                user.x_kpsdk_v = x_kpsdk_v
                user.user_agent = user_agent
                user.crypt_sign = crypt_sign

                # 新上报字段
                user.client_carrier = client_carrier
                user.client_fingerprint = client_fingerprint
                user.client_hardware = client_hardware
                user.client_product = client_product
                user.client_tags = client_tags
                user.client_adb_enabled = client_adb_enabled
                user.client_hook = client_hook
                user.client_development_setting = client_development_setting
                user.email = email

                # 提交即保存到数据库:
                session.commit()
                # 关闭session:
                session.close()
    except:
        traceback.print_exc()
        session.rollback()
        session.close

    return json.dumps({'code': 'success'})


@app.route('/api/veve/ct', methods=['GET'])
def get_ct_list():
    try:
        session = DBSession()
        # 创建新User对象:
        ct_list = session.query(User).all()
        # 关闭session:
        session.close()
        return json.dumps([{"uid": x.uid,  "x-kpsdk-ct": x.x_kpsdk_ct} for x in ct_list])
    except:
        session.rollback()
        session.close()


@app.route('/api/veve/ct', methods=['POST'])
def add_ct():
    sig = request.form.get("sig")
    # if not Utils.getUploadSig().startswith(sig):
    #    return json.dumps({'code': 'error', 'msg': 'invalid sig'})
    uid = request.form.get("uid")
    x_kpsdk_ct = request.form.get("x-kpsdk-ct")
    data = dict()
    try:
        session = DBSession()
        # 创建新User对象:
        up_user = session.query(User).filter(User.uid == uid).first()

        if not up_user:
            data['code'] = 'error'
            data['message'] = '当前用户主体数据还未上报'
        else:
            host_name = up_user.host_name
            up_user.x_kpsdk_ct = x_kpsdk_ct
            if host_name:
                session.commit()
                current_query_user = session.query(User).filter(and_(User.user_type == 'query', User.host_name == host_name)).with_for_update().first()
                if current_query_user:
                    current_query_user.user_type = 'common'
                    up_user.user_type = 'query'
            session.commit()
            # 关闭session:
            session.close()
            data['code'] = 'success'
    except:
        session.rollback()
        session.close()

    return json.dumps(data)


@app.route('/api/veve/log', methods=['POST'])
def add_log():
    uid = request.form.get("uid")
    content = request.form.get("content")
    client_operation = request.form.get("client-operation")
    session = DBSession()
    # 创建新User对象:

    data = dict()
    protocol_log = ProtocolLog(uid=uid, client_operation=client_operation, content=content)
    # 添加到session:
    session.add(protocol_log)
    # 提交即保存到数据库:
    session.commit()
    # 关闭session:
    session.close()
    data['code'] = 'success'
    return json.dumps(data)


@app.route('/api/veve/log', methods=['GET'])
def get_log_list():
    session = DBSession()
    # 创建新User对象:
    log_list = session.query(ProtocolLog).order_by(ProtocolLog.update_time.desc())
    session.close()
    return json.dumps([{"uid": x.uid,  "content": x.content,"update_time": str(x.update_time)} for x in log_list],ensure_ascii=False)


@app.route('/api/veve/results', methods=['GET'])
def get_results_list():
    session = DBSession()

    results_list = session.query(ReserveResult).all()
    # 关闭session:
    session.close()
    return json.dumps([{"id": x.id, "uid": x.uid, "results": x.results,  "create_time":x.create_time} for x in results_list])


@app.route('/api/veve/reservation', methods=['POST'])
def get_reservation_results():
    uid = request.form.get("uid")
    try:
        session = DBSession()
        reservation = session.query(ReserveResult).filter(ReserveResult.uid == uid).first()
        # 关闭session:
        session.close()
        result = reservation.results if reservation else None
        return json.dumps({"code": "success", "data": result})
    except:
        session.rollback()
        session.close()


if __name__ == '__main__':

    app.secret_key = 'watch_codes_up_down-beta'
    app.run(port=3399)